"""
生产服务模块
处理生产任务的创建、分配和状态管理
"""
from sqlmodel import Session, select
from typing import Dict, Any, List, Optional
import requests
import json
import logging
from datetime import datetime
from app.models.order_models import ProductionJob, Manufacturer, Order, OrderStatus

logger = logging.getLogger(__name__)


class ProductionService:
    """
    生产服务类
    负责生产任务的创建、分配和状态管理
    """
    
    def __init__(self, db: Session):
        """
        初始化生产服务
        
        Args:
            db (Session): 数据库会话对象
        """
        self.db = db
    
    def create_production_job(self, order: Order) -> ProductionJob:
        """
        创建生产任务
        为订单分配制造商并创建相应的生产任务
        
        Args:
            order (Order): 订单对象
            
        Returns:
            ProductionJob: 创建的生产任务对象
            
        Raises:
            ValueError: 当没有合适的制造商时抛出
            Exception: 当创建生产任务失败时抛出
        """
        try:
            # 选择合适的制造商
            manufacturer = self._select_manufacturer(order)
            if not manufacturer:
                raise ValueError("没有合适的厂商")
            
            # 生成生产文件URL
            model_file_url = self._generate_production_files(order)
            
            # 生成生产任务编号
            job_number = f"JOB{order.order_number}{int(datetime.utcnow().timestamp())}"
            
            # 创建生产任务记录
            production_job = ProductionJob(
                order_id=order.id,
                manufacturer_id=manufacturer.id,
                job_number=job_number,
                model_file_url=model_file_url,
                production_parameters=order.model_parameters,
                status="pending"
            )
            
            # 保存生产任务
            self.db.add(production_job)
            self.db.commit()
            self.db.refresh(production_job)
            
            # 发送任务给制造商
            self._send_to_manufacturer(production_job, manufacturer)
            
            # 更新订单状态
            order.status = OrderStatus.PROCESSING
            order.updated_at = datetime.utcnow()
            self.db.commit()
            
            logger.info(f"生产任务创建成功: {production_job.job_number}")
            return production_job
            
        except Exception as e:
            # 出现异常时回滚事务
            self.db.rollback()
            logger.error(f"创建生产任务失败: {str(e)}")
            raise
    
    def _select_manufacturer(self, order: Order) -> Optional[Manufacturer]:
        """
        选择合适的制造商
        根据订单要求选择能够处理的活跃制造商
        
        Args:
            order (Order): 订单对象
            
        Returns:
            Optional[Manufacturer]: 选择的制造商对象，如无合适厂商则返回None
        """
        # 查询所有活跃的制造商
        statement = select(Manufacturer).where(Manufacturer.is_active == True)
        manufacturers = self.db.exec(statement).all()
        
        # 检查每个制造商是否有能力处理订单
        for manufacturer in manufacturers:
            if self._check_manufacturer_capability(manufacturer, order):
                return manufacturer
        
        return None
    
    def _check_manufacturer_capability(self, manufacturer: Manufacturer, order: Order) -> bool:
        """
        检查制造商是否有能力处理订单
        根据订单所需材料和制造商支持的材料进行匹配
        
        Args:
            manufacturer (Manufacturer): 制造商对象
            order (Order): 订单对象
            
        Returns:
            bool: 制造商是否能处理订单
        """
        # 获取订单所需的所有材料
        required_materials = set()
        for item in order.order_items:
            required_materials.add(item.material)
        
        # 获取制造商支持的所有材料
        supported_materials = set(manufacturer.supported_materials)
        # 检查订单所需材料是否都在制造商支持的范围内
        return required_materials.issubset(supported_materials)
    
    def _generate_production_files(self, order: Order) -> str:
        """
        生成生产文件URL
        为订单生成用于生产的模型文件URL
        
        Args:
            order (Order): 订单对象
            
        Returns:
            str: 生产文件URL
        """
        return f"https://storage.example.com/models/{order.model_id}/production.stl"
    
    def _send_to_manufacturer(self, production_job: ProductionJob, manufacturer: Manufacturer):
        """
        发送生产任务给制造商
        根据制造商的配置选择API或替代方式发送任务
        
        Args:
            production_job (ProductionJob): 生产任务对象
            manufacturer (Manufacturer): 制造商对象
            
        Raises:
            Exception: 当发送任务失败时抛出
        """
        try:
            # 根据制造商配置选择发送方式
            if manufacturer.api_endpoint:
                self._send_via_api(production_job, manufacturer)
            else:
                self._send_via_alternative(production_job, manufacturer)
            
            # 更新任务状态为已发送
            production_job.status = "sent"
            production_job.sent_at = datetime.utcnow()
            self.db.commit()
            
            logger.info(f"生产任务已发送给厂商: {production_job.job_number}")
            
        except Exception as e:
            logger.error(f"发送生产任务失败: {str(e)}")
            raise
    
    def _send_via_api(self, production_job: ProductionJob, manufacturer: Manufacturer):
        """
        通过API发送生产任务
        调用制造商提供的API接口发送生产任务信息
        
        Args:
            production_job (ProductionJob): 生产任务对象
            manufacturer (Manufacturer): 制造商对象
            
        Raises:
            HTTPError: 当API调用失败时抛出
        """
        # 准备API请求数据
        payload = {
            "job_number": production_job.job_number,
            "order_reference": production_job.order.order_number,
            "model_file_url": production_job.model_file_url,
            "production_parameters": production_job.production_parameters,
            "quantity": len(production_job.order.order_items),
            "materials": [item.material for item in production_job.order.order_items]
        }
        
        # 准备请求头
        headers = {
            'Authorization': f'Bearer {manufacturer.api_key}',
            'Content-Type': 'application/json'
        }
        
        # 发送API请求
        response = requests.post(
            f"{manufacturer.api_endpoint}/production/jobs",
            json=payload,
            headers=headers,
            timeout=30
        )
        
        # 检查响应状态
        response.raise_for_status()
    
    def _send_via_alternative(self, production_job: ProductionJob, manufacturer: Manufacturer):
        """
        通过替代方式发送生产任务
        当制造商没有提供API接口时使用的备选方案
        
        Args:
            production_job (ProductionJob): 生产任务对象
            manufacturer (Manufacturer): 制造商对象
        """
        logger.info(f"通过替代方式发送生产任务给 {manufacturer.name}")
    
    def update_production_status(self, job_number: str, status: str, manufacturer_status: str = None):
        """
        更新生产任务状态
        根据状态更新相应的时间戳
        
        Args:
            job_number (str): 生产任务编号
            status (str): 新的状态
            manufacturer_status (str, optional): 制造商提供的具体状态信息
            
        Raises:
            ValueError: 当生产任务不存在时抛出
        """
        # 查询生产任务
        production_job = self.db.exec(
            select(ProductionJob).where(ProductionJob.job_number == job_number)
        ).first()
        
        if not production_job:
            raise ValueError("生产任务不存在")
        
        # 更新基本状态信息
        production_job.status = status
        production_job.manufacturer_status = manufacturer_status
        production_job.updated_at = datetime.utcnow()
        
        # 根据不同状态更新特定时间戳
        if status == "confirmed" and not production_job.confirmed_at:
            production_job.confirmed_at = datetime.utcnow()
        elif status == "in_production" and not production_job.production_started_at:
            production_job.production_started_at = datetime.utcnow()
        elif status == "completed" and not production_job.production_completed_at:
            production_job.production_completed_at = datetime.utcnow()
            production_job.order.status = OrderStatus.MANUFACTURING
        
        # 提交更改
        self.db.commit()
        logger.info(f"生产状态更新: {job_number} -> {status}")